package com.diver.flinkdemo.utils.excel;


import com.diver.flinkdemo.utils.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.tomcat.util.http.fileupload.IOUtils;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author guofy
 * @create 18/9/4 下午2:46
 * <p>
 * Excel文件 导出 工具类
 **/
public class ExcelExport<T> {
//    private static final Logger log = LoggerFactory.getLogger(ExcelExport.class);

    /**
     * 反射类
     */
    private Class<T> entityClazz;

    public ExcelExport(Class<T> entityClazz) {
        this.entityClazz = entityClazz;
    }

    /**
     * @param dataSet   数据集合 Collection集合子类属性值为null返回空字符串''，为Boolean类型时true返回是，false返回否， 日期格式为设定格式或者默认格式。
     * @param out       输出流对象（存在硬盘中如：newFileOutputStream(filePath)， 存于内存中如：ActionContext.getResponse().getOutputStream()）
     * @param sheetName Excel sheet 页的名称 (默认为sheet1)
     * @throws Exception
     */
    public void exportExcel(Collection<T> dataSet, OutputStream out, String... sheetName) throws Exception {
        // 首先检查数据看是否是正确的
        if (dataSet == null || out == null) {
            throw new IOException("传入的数据不对！");
        }
        String name = "sheet1";
        if (sheetName.length > 0) {
            name = sheetName[0];
        }
        // 得到所有字段
        Field filed[] = entityClazz.getDeclaredFields();
        // 标题列表
        List<String> exportTitleNames = new ArrayList<String>();
        // 日期格式列表
        List<String> dateTimeFormats = new ArrayList<String>();
        // 导出的字段的get方法
        List<Method> methodObj = new ArrayList<Method>();
        List<Map<String, String>> mapList = new ArrayList<>();
        // 遍历整个filed
        for (int i = 0; i < filed.length; i++) {
            Field f = filed[i];
            ExcelAnnotation exa = f.getAnnotation(ExcelAnnotation.class);
            // 如果设置了Annotation
            if (exa != null) {
                // 添加到标题
                exportTitleNames.add(exa.exportTitleName());
                // 添加到日期格式
                dateTimeFormats.add(exa.dateTimeFormat());
                //添加映射类型
                mapList.add(convertMap(exa.mapData()));
                // 添加到需要导出的字段的方法
                String fieldname = f.getName();
                String getMethodName = "get" + fieldname.substring(0, 1).toUpperCase() + fieldname.substring(1);
                Method getMethod = entityClazz.getMethod(getMethodName, new Class[]{});
                methodObj.add(getMethod);
            }
        }
        // 声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 生成一个表格
        HSSFSheet sheet = workbook.createSheet(name);
        // 设置表格默认列宽度为15个字节
        sheet.setDefaultColumnWidth(15);
        // 产生表格标题行
        HSSFRow row = sheet.createRow(0);
        row.setHeightInPoints(24);
        for (int i = 0; i < exportTitleNames.size(); i++) {
            HSSFCell cell = row.createCell(i);
            // 设置标题样式
            cell.setCellStyle(ExcelStyle.setHeadStyle(workbook));
            HSSFRichTextString text = new HSSFRichTextString(exportTitleNames.get(i));
            cell.setCellValue(text);
        }
        int index = 0;
        // 循环整个集合
        HSSFCellStyle bodyStyle = ExcelStyle.setBodyStyle(workbook);
        Iterator<T> its = dataSet.iterator();
        while (its.hasNext()) {
            // 从第二行开始写，第一行是标题
            index++;
            row = sheet.createRow(index);
            row.setHeightInPoints(19);
            T t = its.next();
            for (int k = 0; k < methodObj.size(); k++) {
                HSSFCell cell = row.createCell(k);
                // 设置内容样式
                cell.setCellStyle(bodyStyle);
                Method getMethod = methodObj.get(k);
                Object value = getMethod.invoke(t, new Object[]{});

                //yangs 添加数据映射支持
                String textValue = "";
                if(null != mapList.get(k)){
                    textValue = mapList.get(k).get(value.toString());
                }

                if(StringUtils.isBlank(textValue) && StringUtils.isNoneBlank(dateTimeFormats.get(k))){
                    textValue = getTextValue(value, dateTimeFormats.get(k));
                }

                if(StringUtils.isBlank(textValue)){
                    textValue = null == value ? "" : value.toString();
                }

                cell.setCellValue(textValue);
            }
        }


        workbook.write(out);
    }

    /**
     * 映射
     * @author yangs
     * @param c
     * @return
     */
    private Map<String, String> convertMap(Class c){
        Map<String, String> map = new HashMap<>();
        if(CheckClass.class == c){
            return null;
        }
        if(c.isEnum()){
            try{
                Method m = c.getMethod("values", new Class[]{});
                Method getType = c.getMethod("getType", new Class[]{});
                Method getDesc = c.getMethod("getDesc", new Class[]{});
                Enum[] arr = (Enum[]) m.invoke(c, null);
                for(Enum e : arr){
                    String type = getType.invoke(e, null).toString();
                    String desc = getDesc.invoke(e, null).toString();
                    map.put(type, desc);
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
//                log.error("", e);
                return null;
            }
        }else{
            return null;
        }
        return map;
    }

    private String getTextValue(Object value, String dateTimeFormat) {
        String textValue = "";
        if (value == null) {
            return textValue;
        }
        if (value instanceof Boolean) {
            boolean bValue = (Boolean) value;
            textValue = "是";
            if (!bValue) {
                textValue = "否";
            }
        } else if (value instanceof Date) {
            Date date = (Date) value;
            // 格式化日期
            SimpleDateFormat sdf = new SimpleDateFormat(dateTimeFormat);
            textValue = sdf.format(date);
        } else if (value instanceof Long){
            //yangs 添加long支持

            //数据库数据 是 毫秒 ， 转到 秒
            String str = value.toString();
            String dateStr = str.substring(0, str.length() - 3);
            Long longDate = Long.parseLong(dateStr);

            //解析
            textValue = DateUtil.long2String(longDate, dateTimeFormat);
        }else {
            textValue = value.toString();
        }

        return textValue;
    }



    public static void main(String[] args) throws Exception {

        // 构造一个模拟的List来测试，实际使用时，这个集合用从数据库中查出来
        List<Testpojo> list = new ArrayList<Testpojo>();
        for (int i = 0; i < 20; i++) {
            Testpojo pojo = new Testpojo();
            pojo.setLoginname("登录名" + i);
            pojo.setUsername("用户名" + i);
            pojo.setMoney(new Long(1000 + i));
            pojo.setLogintime(new Date());
            pojo.setCreatetime(new Date());
            pojo.setModifytime(new Date());
            pojo.setAge(28);
            pojo.setSex((i % 3 == 0) ? "男" : "女");
            pojo.setMarriage(i % 3 == 0);
            list.add(pojo);
        }
        // 构造输出对象，可以从response输出，直接向用户提供下载
        OutputStream out = new FileOutputStream("/Users/junlung/Desktop/testOne.xls");
        // 开始时间
        Long l = System.currentTimeMillis();
        // 注意
        ExcelExport<Testpojo> ex = new ExcelExport<Testpojo>(Testpojo.class);
        ex.exportExcel(list, out, "测试");
        out.flush();
        IOUtils.closeQuietly(out);
        // 结束时间
        Long s = System.currentTimeMillis();
        System.out.println("总共耗时：" + (s - l));

    }

}
